package at.ac.univie.ke.neuranetwork;

import java.util.Arrays;
import java.util.HashMap;

import org.neuroph.core.NeuralNetwork;
import org.neuroph.core.data.DataSet;
import org.neuroph.nnet.learning.MomentumBackpropagation;

public class NeuralNetworkTest extends Printer implements Constants{
	private String neuralNetworkConfigFile;
	
	private NeuralNetworkTest(){}
	
	public NeuralNetworkTest(String neuralNetworkConfigFile){
		setNeuralNetworkConfigFile(neuralNetworkConfigFile);
	}
	
	public HashMap<String, TestResult>  executeTests(){
		HashMap<String, TestResult> testResults = new HashMap<String, TestResult>();
		
		//creates a new network for every learning rate and tests it
		for(int i=0; i<LEARNING_RATES.length; i++)
			testResults.put("Test ("+ getNeuralNetworkConfigFile() +") #"+i, testNetwork(LEARNING_RATES[i]) );
		
		return testResults;
	}
	
	public TestResult testNetwork(Double learningRate){
		printInfo(learningRate);
		
		NeuralNetwork<MomentumBackpropagation> neuralNetwork = NeuralNetwork.createFromFile(CONFIG_FILES_BASE_DIR + "/" + getNeuralNetworkConfigFile());
		
		DataSet trainingsset=DataSet.load(TRAININGS_SET);
		DataSet testset=DataSet.load(TEST_SET);
		
		MomentumBackpropagation learningRule=new MomentumBackpropagation();
		learningRule.setMaxError(MAX_ERROR);
		learningRule.setMaxIterations(MAX_ITERATION);
		learningRule.setMomentum(MOMENTUM);
		learningRule.setLearningRate(learningRate);
		
		neuralNetwork.learn(trainingsset, learningRule);
		
		TestResult testResult = new TestResult();
		testResult.setTotalNetworkError( learningRule.getTotalNetworkError() );
		
		Evaluation evaluation = new Evaluation(neuralNetwork, new MeanSquaredError());		
		testResult.setMeanDistance( evaluation.meanDistance(testset) );
		
		testResult.setNetwork(getNeuralNetworkConfigFile());
		testResult.setLearningRate(learningRate);

		FileHandler myFileHandler = new FileHandler(CUSTOM_IMAGE_BASE_DIR);
		
		double threeDoubles[] = myFileHandler.getCustomImage(3);
		double fiveDoubles[] = myFileHandler.getCustomImage(5);
		double eightDoubles[] = myFileHandler.getCustomImage(8);
		double nineDoubles[] = myFileHandler.getCustomImage(9);
		
		
		//testCustomImage(3, threeDoubles, neuralNetwork);
		//testCustomImage(5, fiveDoubles, neuralNetwork);
		testCustomImage(8, eightDoubles, neuralNetwork);
		testCustomImage(9, nineDoubles, neuralNetwork);
		
		return testResult;
		
	}
	
	public void printInfo(double learningRate){
		drawLine();
		System.out.println("loading network (" + CONFIG_FILES_BASE_DIR + "/" + getNeuralNetworkConfigFile() + ") ...");
		System.out.println("config: ");
		System.out.println("\tmax error: " + MAX_ERROR);
		System.out.println("\tmax iteration: " + MAX_ITERATION);
		System.out.println("\tmomentum: " + MOMENTUM);
		System.out.println("\tlearing rate: " + learningRate);
		
		drawLine();
		drawSpace();
		
	}
	
	public void testCustomImage(int label, double[] imageData, NeuralNetwork<MomentumBackpropagation> neuralNetwork){
		neuralNetwork.setInput(imageData);
		neuralNetwork.calculate();
		double[] networkOutput = neuralNetwork.getOutput();

		drawLine();
		System.out.println("Expected:" + label);
		System.out.println("Result:");
		System.out.print(Arrays.toString(networkOutput) );
		drawLine();
		drawSpace();
	}

	public String getNeuralNetworkConfigFile() {
		return neuralNetworkConfigFile;
	}

	public void setNeuralNetworkConfigFile(String neuralNetworkConfigFile) {
		this.neuralNetworkConfigFile = neuralNetworkConfigFile;
	}

}
